package hu.bme.mit.androtext.data.serializer;

import com.google.inject.Inject;
import com.google.inject.Provider;
import hu.bme.mit.androtext.data.androData.AndroDataPackage;
import hu.bme.mit.androtext.data.androData.AndroDataRoot;
import hu.bme.mit.androtext.data.androData.DataTypeRef;
import hu.bme.mit.androtext.data.androData.Entity;
import hu.bme.mit.androtext.data.androData.EntityTypeRef;
import hu.bme.mit.androtext.data.androData.Feature;
import hu.bme.mit.androtext.data.services.AndroDataGrammarAccess;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.serializer.acceptor.ISemanticSequenceAcceptor;
import org.eclipse.xtext.serializer.acceptor.SequenceFeeder;
import org.eclipse.xtext.serializer.diagnostic.ISemanticSequencerDiagnosticProvider;
import org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic.Acceptor;
import org.eclipse.xtext.serializer.sequencer.AbstractSemanticSequencer;
import org.eclipse.xtext.serializer.sequencer.GenericSequencer;
import org.eclipse.xtext.serializer.sequencer.ISemanticNodeProvider.INodesForEObjectProvider;
import org.eclipse.xtext.serializer.sequencer.ISemanticSequencer;
import org.eclipse.xtext.serializer.sequencer.ITransientValueService;
import org.eclipse.xtext.serializer.sequencer.ITransientValueService.ValueTransient;

@SuppressWarnings("restriction")
public class AbstractAndroDataSemanticSequencer extends AbstractSemanticSequencer {

	@Inject
	protected AndroDataGrammarAccess grammarAccess;
	
	@Inject
	protected ISemanticSequencerDiagnosticProvider diagnosticProvider;
	
	@Inject
	protected ITransientValueService transientValues;
	
	@Inject
	@GenericSequencer
	protected Provider<ISemanticSequencer> genericSequencerProvider;
	
	protected ISemanticSequencer genericSequencer;
	
	
	@Override
	public void init(ISemanticSequencer sequencer, ISemanticSequenceAcceptor sequenceAcceptor, Acceptor errorAcceptor) {
		super.init(sequencer, sequenceAcceptor, errorAcceptor);
		this.genericSequencer = genericSequencerProvider.get();
		this.genericSequencer.init(sequencer, sequenceAcceptor, errorAcceptor);
	}
	
	public void createSequence(EObject context, EObject semanticObject) {
		if(semanticObject.eClass().getEPackage() == AndroDataPackage.eINSTANCE) switch(semanticObject.eClass().getClassifierID()) {
			case AndroDataPackage.ANDRO_DATA_ROOT:
				if(context == grammarAccess.getAndroDataRootRule()) {
					sequence_AndroDataRoot(context, (AndroDataRoot) semanticObject); 
					return; 
				}
				else break;
			case AndroDataPackage.DATA_TYPE_REF:
				if(context == grammarAccess.getDataTypeRefRule() ||
				   context == grammarAccess.getTypeRefRule()) {
					sequence_DataTypeRef(context, (DataTypeRef) semanticObject); 
					return; 
				}
				else break;
			case AndroDataPackage.ENTITY:
				if(context == grammarAccess.getEntityRule() ||
				   context == grammarAccess.getTypeRule()) {
					sequence_Entity(context, (Entity) semanticObject); 
					return; 
				}
				else break;
			case AndroDataPackage.ENTITY_TYPE_REF:
				if(context == grammarAccess.getEntityTypeRefRule() ||
				   context == grammarAccess.getTypeRefRule()) {
					sequence_EntityTypeRef(context, (EntityTypeRef) semanticObject); 
					return; 
				}
				else break;
			case AndroDataPackage.FEATURE:
				if(context == grammarAccess.getFeatureRule()) {
					sequence_Feature(context, (Feature) semanticObject); 
					return; 
				}
				else break;
			}
		if (errorAcceptor != null) errorAcceptor.accept(diagnosticProvider.createInvalidContextOrTypeDiagnostic(semanticObject, context));
	}
	
	/**
	 * Constraint:
	 *     (name=ID types+=Type*)
	 *
	 * Features:
	 *    name[1, 1]
	 *    types[0, *]
	 */
	protected void sequence_AndroDataRoot(EObject context, AndroDataRoot semanticObject) {
		genericSequencer.createSequence(context, semanticObject);
	}
	
	
	/**
	 * Constraint:
	 *     (referencedDataType=DataTypes multi?='*'?)
	 *
	 * Features:
	 *    multi[0, 1]
	 *    referencedDataType[1, 1]
	 */
	protected void sequence_DataTypeRef(EObject context, DataTypeRef semanticObject) {
		genericSequencer.createSequence(context, semanticObject);
	}
	
	
	/**
	 * Constraint:
	 *     (referenced=[Entity|ID] multi?='*'?)
	 *
	 * Features:
	 *    multi[0, 1]
	 *    referenced[1, 1]
	 */
	protected void sequence_EntityTypeRef(EObject context, EntityTypeRef semanticObject) {
		genericSequencer.createSequence(context, semanticObject);
	}
	
	
	/**
	 * Constraint:
	 *     (name=ID superType=[Entity|ID]? features+=Feature*)
	 *
	 * Features:
	 *    name[1, 1]
	 *    superType[0, 1]
	 *    features[0, *]
	 */
	protected void sequence_Entity(EObject context, Entity semanticObject) {
		genericSequencer.createSequence(context, semanticObject);
	}
	
	
	/**
	 * Constraint:
	 *     (name=ID type=TypeRef)
	 *
	 * Features:
	 *    name[1, 1]
	 *    type[1, 1]
	 */
	protected void sequence_Feature(EObject context, Feature semanticObject) {
		if(errorAcceptor != null) {
			if(transientValues.isValueTransient(semanticObject, AndroDataPackage.Literals.FEATURE__NAME) == ValueTransient.YES)
				errorAcceptor.accept(diagnosticProvider.createFeatureValueMissing(semanticObject, AndroDataPackage.Literals.FEATURE__NAME));
			if(transientValues.isValueTransient(semanticObject, AndroDataPackage.Literals.FEATURE__TYPE) == ValueTransient.YES)
				errorAcceptor.accept(diagnosticProvider.createFeatureValueMissing(semanticObject, AndroDataPackage.Literals.FEATURE__TYPE));
		}
		INodesForEObjectProvider nodes = createNodeProvider(semanticObject);
		SequenceFeeder feeder = createSequencerFeeder(semanticObject, nodes);
		feeder.accept(grammarAccess.getFeatureAccess().getNameIDTerminalRuleCall_1_0(), semanticObject.getName());
		feeder.accept(grammarAccess.getFeatureAccess().getTypeTypeRefParserRuleCall_3_0(), semanticObject.getType());
		feeder.finish();
	}
}
